<?php
/**
 * Created by PhpStorm.
 * User: 小灰灰
 * Date: 2022-08-18
 * Time: 16:14:11
 * Info:
 */

namespace app\admin\controller\plugin;

use app\admin\annotation\ControllerAnnotation;
use app\admin\annotation\NodeAnotation;
use app\admin\controller\CommonController;
use support\Request;
use support\lib\Backup;
use app\common\model\AuthMenu as AuthMenuModel;
use app\common\model\AuthRule as AuthRuleModel;
use support\Cache;

/**
 * @ControllerAnnotation(title="插件管理")
 * Class Node
 * @package app\admin\controller\plugin
 */
class IndexController extends CommonController
{

    public $plugin_path;

    static $errData = [];

    public function __construct()
    {
        $this->plugin_path = plugin_path();
    }

    /**
     * @NodeAnotation(title="插件列表")
     */
    public function index(Request $request)
    {
        $path = $this->getPlugins();
        if ($request->isAjax()) {
            return $this->success('ok', $path, count($path));
        }

        return view('plugin/index');
    }

    /**
     * @NodeAnotation(title="创建插件")
     */
    public function add(Request $request)
    {
        if ($request->isPost()) {
            $param    = $request->post();
            $validate = (new \think\Validate)->rule([
                'name|插件标识'    => 'require|length:2,12|alpha',
                'title|插件名称'   => 'require',
                'version|插件版本' => 'require',
                'author|插件作者'  => 'require',
            ]);
            $validate->message([
                'name.require'   => '插件标识不能为空',
                'name.length'    => '插件标识长度必须2-12之间',
                'name.alpha'     => '插件标识只能为字母',
                'title.require'  => '插件名称不能为空',
                'author.require' => '插件作者不能为空',
            ]);
            if ( ! $validate->check($param)) {
                return $this->error($validate->getError());
            }
            //查询插件名称是否已存在
            $getNameDir = plugin_path($param['name']);
            if (is_dir($getNameDir)) {
                return $this->error('该插件名称已经存在啦');
            }
            self::createAdd($param);

            system_reload();

            return $this->success('创建成功，可以愉快的开发插件啦');

        }

        return view('plugin/add');
    }

    /**
     * @NodeAnotation(title="安装插件")
     */
    public function install(Request $request)
    {
        if ($request->isAjax()) {
            $name = $request->input('name');
            if (empty($name)) {
                return error_json('参数错误');
            }
            $pluginPath  = plugin_path($name);
            $fileInstall = $pluginPath.'install.lock';
            if (file_exists($fileInstall)) {
                return error_json('请勿重复安装插件');
            }
            try {
                $pluginClass = get_plugin_instance($name);
                $pluginClass->install();
                self::pluginMenu($name, 1);
                self::executeSql($name);
                self::enabled($name);
                self::installLock($name);
                system_reload();
            } catch (\Throwable $th) {
                //recursive_delete($pluginPath);

                return error_json($th->getMessage(), null, self::$errData, $th->getCode());
            }

            return $this->success('插件安装成功', null, get_plugin_config($name, true));
        }
    }

    /**
     * @NodeAnotation(title="卸载插件")
     */
    public function uninstall(Request $request)
    {
        if ($request->isAjax()) {
            $name   = $request->input('name');
            $config = get_plugin_config($name, true);

            if (empty($config) || $config['status'] != 0) {
                return error_json('插件不存在或未禁用');
            }
            try {
                $pluginClass = get_plugin_instance($name);
                $pluginClass->uninstall();
                //开发环境同时是超级管理员，指向删除的sql语句
                if (get_env('APP.APP_DEBUG') && cmf_get_role_id() == 1) {
                    self::pluginMenu($name, 0);
                    self::executeSql($name, 'uninstall');
                }
                set_plugin_config($name, ['status' => 0]);
                self::deleteLock($name);
                system_reload();
                //plugin_refresh_hooks();
            } catch (\Throwable $th) {
                return error_json($th->getMessage());
            }

            return $this->success('插件卸载成功');

        }
    }

    /**
     * @NodeAnotation(title="删除插件")
     */
    public function delete(Request $request)
    {
        $name = $request->get('name');
        if (empty($name)) {
            return error_json('参数错误');
        }
        $pluginPath = $this->plugin_path.$name;
        if ( ! is_dir($pluginPath)) {
            return error_json('该插件不存在或者已经被删除');
        }
        //判断是否已安装
        $installFile = $pluginPath.DIRECTORY_SEPARATOR.'install.lock';
        if (file_exists($installFile)) {
            return error_json('请先卸载后再删除');
        }
        dir_delete($pluginPath);

        return $this->success('删除成功');
    }

    /**
     * @NodeAnotation(title="插件设置")
     */
    public function config(Request $request)
    {
        $name   = $request->input('name');
        $config = get_plugin_config(strtolower($name), true);
        if (preg_replace('/[^a-zA-Z0-9]/i', '', $name) !== $name) {
            return error_json('插件名称只能是字母和数字');
        }

        if (empty($config)) {
            return error_json('插件不存在');
        }

        if ($request->isPost()) {
            $rewrite_key   = $request->input('rewrite_key');
            $rewrite_value = $request->input('rewrite_value');
            $rewrite       = [];
            if (empty($rewrite_key)) {
                $rewrite_key   = [];
                $rewrite_value = [];
            }

            foreach ($rewrite_key as $k => $v) {
                $rewrite1['key']   = $v;
                $rewrite1['value'] = $rewrite_value[$k];
                $rewrite[]         = $rewrite1;
            }
            $post['extends'] = $request->input('extends');
            $post['rewrite'] = $rewrite;
            $config          = array_merge($config, $post);
            try {
                set_plugin_config($name, $config);
            } catch (\Throwable $th) {
                return error_json($th->getMessage());
            }

            return $this->success('保存成功');
        }

        if ( ! file_exists($config['path'].'/config.html')) {
            return error_json('配模板不存在');
        }

        return view($config['path'].'/config.html', ['config' => $config]);
    }

    /**
     * @NodeAnotation(title="修改状态")
     */
    public function enable(Request $request)
    {
        if (request()->isAjax()) {
            $name = $request->input('name');
            $val  = $request->input('val');

            $pluginPath  = $this->plugin_path.$name;
            $installFile = $pluginPath.DIRECTORY_SEPARATOR.'install.lock';
            if ( ! file_exists($installFile)) {
                return error_json('请先安装');
            }

            set_plugin_config($name, ['status' => $val]);

            return $this->success('ok');
        }
    }

    private function getPlugins()
    {
        $pluginPath = $this->plugin_path;
        $paths      = glob($pluginPath.'*');
        foreach ($paths as $key => $p) {
            if (is_dir($p)) {
                $info = $p.DIRECTORY_SEPARATOR.'config.json';
                if ( ! file_exists($info)) {
                    unset($paths[$key]);
                }
            }
        }

        $return = [];
        foreach ($paths as $v) {
            $plugin_path1 = explode(DIRECTORY_SEPARATOR, $v);
            $config       = get_plugin_config(end($plugin_path1));

            $statusFile = $v.DIRECTORY_SEPARATOR.'install.lock';
            $status     = file_exists($statusFile) ? 1 : 0;

            $configFile = $v.DIRECTORY_SEPARATOR.'config.html';
            $is_config  = file_exists($configFile) ? 1 : 0;

            $return[] = [
                'file_path'   => $v,
                'plugin_path' => end($plugin_path1),
                'name'        => ! empty($config['name']) ? $config['name'] : '',
                'title'       => ! empty($config['title']) ? $config['title'] : '',
                'intro'       => ! empty($config['intro']) ? $config['intro'] : '',
                'version'     => ! empty($config['version']) ? $config['version'] : '',
                'author'      => ! empty($config['author']) ? $config['author'] : '',
                'status'      => ! empty($config['status']) ? $config['status'] : 0,
                'enable'      => $status,
                'is_config'   => $is_config
            ];
        }

        return $return;
    }

    /**
     * 获取菜单项
     *
     * @param string $name
     * @param int    $type 菜单类型，1=安装；2=卸载
     *
     * @return void
     */
    public static function pluginMenu($name, $type = 1)
    {
        $pluginPath = plugin_path($name);
        $pluginMenu = $pluginPath.'data/menu.php';
        if (is_file($pluginMenu)) {
            $data = include($pluginMenu);
            if ($type == 1) {
                if ( ! empty($data['auth_menu'])) {
                    $menuId = 0;
                    foreach ($data['auth_menu'] as $v) {
                        //判断是否包含type=0的【目录】，如果有，其子级的pid取值父级的id
                        if ($v['type'] == 0) {
                            //如果pid不是数字而是url-node值，则取值对应的父级id替换pid在写入
                            if ( ! is_numeric($v['pid'])) {
                                $findID   = AuthMenuModel::where('node', $v['pid'])->value('id');
                                $v['pid'] = $findID;
                            }
                            $menuId = AuthMenuModel::insertGetId($v);
                        } else {
                            //如果是数字，pid对应的是父级id，直接写入
                            if (is_numeric($v['pid'])) {
                                if ($menuId != 0) {
                                    $v['pid'] = $menuId;
                                }
                                AuthMenuModel::create($v);
                            } else {
                                //如果pid不是数字而是url-node值，则取值对应的父级id替换pid在写入
                                $findID = AuthMenuModel::where('node', $v['pid'])->value('id');
                                if ( ! empty($findID)) {
                                    $v['pid'] = $findID;
                                    AuthMenuModel::create($v);
                                }
                            }
                        }
                    }
                }
                if ( ! empty($data['auth_rule'])) {
                    foreach ($data['auth_rule'] as $key => $v) {
                        $data['auth_rule'][$key]['is_plugin']   = 1;
                        $data['auth_rule'][$key]['create_time'] = time();
                        $data['auth_rule'][$key]['update_time'] = time();
                    }
                    AuthRuleModel::insertAll($data['auth_rule']);
                }
            } else {
                if ( ! empty($data['auth_menu'])) {
                    if (count($data['auth_menu']) == count($data['auth_menu'], 1)) {
                        return false;
                    }
                    foreach ($data['auth_menu'] as $v) {
                        AuthMenuModel::where('node', $v['node'])->delete();
                    }
                }
                if ( ! empty($data['auth_rule'])) {
                    foreach ($data['auth_rule'] as $v) {
                        AuthRuleModel::where('node', $v['node'])->delete();
                    }
                }
            }
            Cache::clear();
        }
    }

    /**
     * 执行SQL脚本文件
     *
     * @param string $name
     * @param string $type
     *
     * @return void
     */
    public static function executeSql($name, $type = 'install')
    {
        $pluginPath = plugin_path($name);
        $sqlFile    = $pluginPath.$type.'.sql';
        if (file_exists($sqlFile)) {
            BackUp::importSql($sqlFile);
        }
    }

    /**
     * 启用插件
     *
     * @param string $name
     *
     * @return bool
     */
    public static function enabled($name)
    {
        set_plugin_config($name, ['status' => 1]);
    }

    /**
     * 禁用插件
     *
     * @param string $name
     *
     * @return void
     */
    public static function disabled($name)
    {
        set_plugin_config($name, ['status' => 0]);
    }

    /**
     * 创建insta.lock 文件
     *
     * @param $name
     *
     * @return void
     */
    public static function installLock($name)
    {
        $pluginPath  = plugin_path($name);
        $fileInstall = $pluginPath.'install.lock';
        file_put_contents($fileInstall, 1);
    }

    /**
     * 创建insta.lock 文件
     *
     * @param $name
     *
     * @return void
     */
    public static function deleteLock($name)
    {
        $pluginPath  = plugin_path($name);
        $fileInstall = $pluginPath.'install.lock';
        unlink($fileInstall);
    }

    /**
     * 创建插件对应的文件夹和文件
     * @return void
     */
    public static function createAdd($param)
    {
        //创建文件夹
        self::createAddDir($param['name']);
        ////创建配置文件、安装/卸载sql
        self::createAddFiles($param);
        //创建其他文件
        self::writeOtherFiles($param['name']);
    }

    /**
     * 创建对应文件夹
     * @return void
     */
    private static function createAddDir($name)
    {
        mk_dirs('plugin'.DIRECTORY_SEPARATOR.$name.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'controller');
        mk_dirs('plugin'.DIRECTORY_SEPARATOR.$name.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'model');
        mk_dirs('plugin'.DIRECTORY_SEPARATOR.$name.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR.'view');
        mk_dirs('plugin'.DIRECTORY_SEPARATOR.$name.DIRECTORY_SEPARATOR.'config');
        mk_dirs('plugin'.DIRECTORY_SEPARATOR.$name.DIRECTORY_SEPARATOR.'data');
    }

    /**
     * 创建配置文件、安装/卸载sql
     *
     * @param $param
     */
    private static function createAddFiles($param)
    {
        $path = plugin_path($param['name']);
        //复制文件模板
        $copyPath = public_path().DIRECTORY_SEPARATOR.'tpl'.DIRECTORY_SEPARATOR.'plugin';
        recursive_dir_copy($copyPath, $path);
        if (isset($param['menu']) && $param['menu'] == 0) {
            dir_delete($path.'data');
        }
        unset($param['menu']);
        if (isset($param['config']) && $param['config'] == 0) {
            @unlink($path.'config.html');
        }

        $jsonData = $param;
        write_file($path.'config.json', json_encode($jsonData, JSON_UNESCAPED_UNICODE));

        return true;
    }

    private static function writeOtherFiles($name)
    {
        $writeData1 = self::templatePhpOne('one', $name);
        //创建部分文件数据
        $path = plugin_path($name);
        write_file($path.ucfirst($name).'.php', $writeData1);
    }

    private static function templatePhpOne($t, $name)
    {
        $writeData = '';

        if ($t === 'one') {
            $writeData = "<?php

namespace plugin\\$name;

class ".ucfirst($name)."
{

    /**
     * 插件安装方法
     * @return bool
     */
    public function install()
    {
        return true;
    }

    /**
     * 插件卸载方法
     * @return bool
     */
    public function uninstall()
    {
        return true;
    }

    /**
     * 插件启用方法
     * @return bool
     */
    public function enabled()
    {
        return true;
    }

    /**
     * 插件禁用方法
     * @return bool
     */
    public function disabled()
    {
        return true;
    }

    /**
     * 测试HOOK API
     * 自定义钩子
     * @return bool
     */
    public function linkhook(\$params)
    {

    }

}
";
        }

        return $writeData;
    }

}
